﻿using ManagementApi.Models.Manage.ProjectGroupMember;
using Modules;
using Modules.Attachment;
using Modules.BankSpecialAccount;
using Modules.CheckIn;
using Modules.CheckIn.Entitys;
using Modules.CheckInCount;
using Modules.Payroll;
using Modules.Person;
using Modules.Project;
using Modules.Reports;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Exceptions;
using System.ComponentModel.DataAnnotations;
using static Modules.Payroll.PayrollConstants;

namespace ManagementApi.Models.Payroll
{
    public static class PayrollExtensions
    {
        public static PayrollDetailDto AsPayrollDto(this WagePayroll entity)
        {
            var payrollService = ServiceAccessor.GetService<WagePayrollService>();
            var projectCorpService = ServiceAccessor.GetService<ProjectCorpService>();
            var reportProjectMonthService = ServiceAccessor.GetService<ReportProjectMonthService>();
            var projectService = ServiceAccessor.GetService<ProjectService>();
            var project = projectService.GetProjectInfo(entity.ProjectId) ?? throw new BusinessException("项目不存在");
            decimal contractAmount = 0;
            ReportProjectMonth? reportProjectMonth = reportProjectMonthService.GetReportProjectMonthByProjectIdAndMonth(entity.ProjectId, entity.Month);
            PayrollDto payrollDto = entity.AsDto();
            PayrollDetailDto dto = new();
            if (entity.CorpId == project.LumpContractorCorpId)
            {
                contractAmount = project.ContractAmount ?? 0;
            }
            else
            {
                contractAmount = projectCorpService.GetProjectCorpByProjectIdAndCorpId(payrollDto.ProjectId, payrollDto.CorpId)?.ContractAmount ?? 0;
            }
            dto.ProjectName = payrollDto.ProjectName;
            dto.CorpName = payrollDto.CorpName;
            dto.TotalExpenditure = payrollService.GetSumWagePayrollsSuccessfulAmount(payrollDto.ProjectId, payrollDto.CorpId);
            dto.Month = payrollDto.Month;
            if (reportProjectMonth != null)
                dto.Days = reportProjectMonth.DaysThisMonthUnderConstruction;
            dto.TotalValuation = payrollDto.TotalValuation;
            dto.RemainingAmount = contractAmount - dto.TotalExpenditure;
            dto.Code = payrollDto.Code;
            dto.AmountApplied = payrollDto.AmountApplied;
            dto.SuccessfulAmount = payrollDto.SuccessfulAmount ?? 0;
            dto.FailureAmount = payrollDto.FailureAmount ?? 0;
            dto.WageStatus = entity.WageStatus;
            dto.WageStatusName = entity.WageStatus.GetDescription();
            dto.WageSuccessPersonCount = entity.WageSuccessPersonCount ?? 0;
            dto.QueryResultResponse = entity.QueryResultResponse;
            dto.BatchNo = entity.BatchNo ?? string.Empty;
            return dto;
        }

        /// <summary>
        /// 将工资单明细数据转换成工资单明细数据（有明细数据）
        /// </summary>
        /// <param name="payrollDetails"></param>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static PayrollDetailDto AsPayrollDetailDto(this IEnumerable<WagePayrollDetail> payrollDetails, WagePayroll entity, IApplicationContext applicationContext)
        {
            var workHoursService = applicationContext.GetService<CheckinWorkHoursService>();
            var projectService = applicationContext.GetService<ProjectService>();
            var projectGroupService = applicationContext.GetService<ProjectGroupService>();
            var bankSpecialAccountService = applicationContext.GetService<BankSpecialAccountService>();
            var personService = applicationContext.GetService<PersonService>();

            var projectInfo = projectService.GetProjectInfo(entity.ProjectId);
            var groups = projectGroupService.GetProjectGroups(payrollDetails.Select(m => m.GroupId).Distinct());
            PayrollDto payrollDto = entity.AsDto();
            PayrollDetailDto dto = entity.AsPayrollDto();

            int year = int.Parse(payrollDto.Month.ToString().Substring(0, 4)),
               month = int.Parse(payrollDto.Month.ToString().Substring(4, 2));

            var workHours = workHoursService.GetCheckinWorkHoursByMonthAndMemberIds(payrollDto.Month, payrollDetails.Where(m => m.MemberId > 0).Select(m => m.MemberId).Distinct());
            var account = bankSpecialAccountService.GetProjectSpecialAccountByProjectId(entity.ProjectId).FirstOrDefault() ?? throw new BusinessException("专户信息错误");
            var project = projectService.GetProjectInfo(entity.ProjectId);
            var persons = personService.GetPersons(payrollDetails.Select(i => i.PersonId));

            List<PayrollDetailsDto> details = new();

            foreach (var item in payrollDetails)
            {
                PayrollDetailsDto payrollDetailsDto = new()
                {
                    ProjectName = projectInfo?.Name ?? "未知项目",
                    GroupName = groups.FirstOrDefault(m => m.GroupId == item.GroupId)?.Name ?? "未知组",
                    WorkType = item.WorkType.GetDescription("未知"),
                    PersonName = item.PersonName,
                    IdCard = item.IdCard,
                    PersonBankNo = item.BankCardNo,
                    BankName = item.BankName,
                    AmountApplied = item.AmountApplied,
                    AmountPaid = item.AmountPaid ?? 0,
                    Status = item.Status,
                    StatusName = item.Status.GetDescription(),
                    IssueTime = item.IssueTime,
                    FailReason = item.FailReason,
                    AttendanceDays = workHours.FirstOrDefault(m => m.MemberId == item.MemberId)?.CheckinDay ?? 0
                };
                details.Add(payrollDetailsDto);
            }

            if (applicationContext.CurrentUser?.Type == PmSoft.Entity.UserType.Constructor || applicationContext.CurrentUser?.Type == PmSoft.Entity.UserType.Commander)
            {
                dto.NeedVerify = true;
                dto.VerifyName = account.ConstructorChecker;
                dto.VerifyMobile = account.ConstructorMobile;
            }
            if (applicationContext.CurrentUser?.Type == PmSoft.Entity.UserType.Corp)
            {
                dto.NeedVerify = true;
                dto.VerifyName = account.LumpContractorCorpChecker;
                dto.VerifyMobile = account.LumpContractorCorpMobile;
            }

            dto.Details = details;
            return dto;
        }

        /// <summary>
        /// 将班组成员数据转换成工资单明细数据(无明细数据)
        /// </summary>
        /// <param name="members"></param>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static PayrollDetailDto AsPayrollDetailDto(this IEnumerable<ProjectGroupMemberDto> members, WagePayroll entity)
        {
            PayrollDto payrollDto = entity.AsDto();
            PayrollDetailDto dto = entity.AsPayrollDto();
            var checkInDetailService = ServiceAccessor.GetService<CheckInDetailService>();
            List<PersonCount> personCounts = checkInDetailService.GetPersonCountsByProjectIdGroupPersonAndGroupId(new ProjectCheckinCountQuery() { ProjectId = payrollDto.ProjectId, Month = payrollDto.Month }).ToList();
            List<PayrollDetailsDto> details = new();
            foreach (var item in members)
            {
                PayrollDetailsDto payrollDetailsDto = new()
                {
                    ProjectName = item.ProjectName,
                    GroupName = item.GroupName,
                    WorkType = item.TypeName,
                    PersonName = item.PersonName,
                    IdCard = item.CardNumber,
                    PersonBankNo = item.BankCardNo,
                    BankName = item.BankName,
                };
                payrollDetailsDto.AttendanceDays = personCounts.FirstOrDefault(a => a.GroupId == item.GroupId && a.PersonId == item.PersonId)?.Count ?? 0;
                details.Add(payrollDetailsDto);
            }
            dto.Details = details;
            return dto;
        }
    }

    /// <summary>
    /// 明细主数据
    /// </summary>
    public class PayrollDetailDto
    {
        /// <summary>
        /// 项目名称
        /// </summary>
        public string ProjectName { get; set; }

        /// <summary>
        /// 劳务公司
        /// </summary>
        public string CorpName { get; set; }

        /// <summary>
        /// 总支出额
        /// </summary>
        public decimal TotalExpenditure { get; set; }

        /// <summary>
        /// 发放月份
        /// </summary>
        public int Month { get; set; }

        /// <summary>
        /// 当月应考勤天数
        /// </summary>
        public int Days { get; set; }

        /// <summary>
        /// 当月计价总额
        /// </summary>
        public decimal? TotalValuation { get; set; }

        /// <summary>
        /// 剩余合同金额
        /// </summary>
        public decimal RemainingAmount { get; set; }

        /// <summary>
        /// 流水号
        /// </summary>
        public string Code { get; set; }

        /// <summary>
        /// 申请金额
        /// </summary>
        public decimal? AmountApplied { get; set; }

        /// <summary>
        /// 成功金额
        /// </summary>
        public decimal SuccessfulAmount { get; set; }

        /// <summary>
        /// 失败金额
        /// </summary>
        public decimal FailureAmount { get; set; }

        /// <summary>
        /// 代发状态
        /// </summary>
        public 代发状态 WageStatus { get; set; }

        /// <summary>
        /// 代发批次号
        /// </summary>
        public string BatchNo { get; set; }

        /// <summary>
        /// 代发状态
        /// </summary>
        public string WageStatusName { get; set; } = string.Empty;

        /// <summary>
        /// 代发成功人数
        /// </summary>
        public int? WageSuccessPersonCount { get; set; }

        /// <summary>
        /// 最近一次获取代发结果错误信息
        /// </summary>
        public string QueryResultResponse { get; set; } = string.Empty;

        /// <summary>
        /// 审核是否需要验证手机号
        /// </summary>
        public bool NeedVerify { get; set; } = false;

        /// <summary>
        /// 验证人
        /// </summary>
        public string VerifyName { get; set; } = string.Empty;

        /// <summary>
        /// 验证人手机号
        /// </summary>
        public string VerifyMobile { get; set; } = string.Empty;

        /// <summary>
        /// 明细
        /// </summary>
        public IEnumerable<PayrollDetailsDto> Details { get; set; }

        /// <summary>
        /// 合同附件
        /// </summary>
        [Display(Name = "合同附件")]
        public IEnumerable<AttachmentsForm<int>> Attachments { get; set; }
    }

    /// <summary>
    /// 明细
    /// </summary>
    public class PayrollDetailsDto
    {
        /// <summary>
        /// 项目名称
        /// </summary>
        [Display(Name = "项目名称")]
        public string ProjectName { get; set; } = string.Empty;

        /// <summary>
        /// 班组名称
        /// </summary>
        [Display(Name = "班组名称")]
        public string GroupName { get; set; } = string.Empty;

        /// <summary>
        /// 班组Id
        /// </summary>
        [Display(Name = "班组Id")]
        public int? GroupId { get; set; }

        /// <summary>
        /// 工种
        /// </summary>
        [Display(Name = "工种")]
        public string WorkType { get; set; }

        /// <summary>
        /// 人员姓名
        /// </summary>
        [Display(Name = "人员姓名")]
        public string PersonName { get; set; } = string.Empty;

        /// <summary>
        /// 人员身份证号码
        /// </summary>
        [Display(Name = "人员身份证号码")]
        public string IdCard { get; set; } = string.Empty;

        /// <summary>
        /// 银行卡号
        /// </summary>
        [Display(Name = "银行卡号")]
        public string PersonBankNo { get; set; } = string.Empty;

        /// <summary>
        /// 开户行名称
        /// </summary>
        [Display(Name = "开户行名称")]
        public string BankName { get; set; } = string.Empty;

        /// <summary>
        /// 考勤天数
        /// </summary>
        [Display(Name = "考勤天数")]
        public int AttendanceDays { get; set; }

        /// <summary>
        /// 申请金额
        /// </summary>
        [Display(Name = "申请金额")]
        public decimal? AmountApplied { get; set; } = 0;

        /// <summary>
        /// 实发金额
        /// </summary>
        [Display(Name = "实发金额")]
        public decimal AmountPaid { get; set; } = 0;

        /// <summary>
        /// 工资发放状态
        /// </summary>
        [Display(Name = "工资发放状态")]
        public 工资发放状态 Status { get; set; }

        /// <summary>
        /// 工资发放状态
        /// </summary>
        [Display(Name = "工资发放状态")]
        public string StatusName { get; set; } = string.Empty;

        /// <summary>
        /// 发放时间
        /// </summary>
        [Display(Name = "发放时间")]
        public DateTime? IssueTime { get; set; }

        /// <summary>
        /// 代发失败原因
        /// </summary>
        [Display(Name = "代发失败原因")]
        public string FailReason { get; set; } = string.Empty;
    }
}